package source;

/*
This file is free software; you can redistribute it and/or modify it under
the terms of the GNU General Public License version 2, 1991 as published by
the Free Software Foundation.

This program is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more
details.

A copy of the GNU General Public License can be found at:
http://www.gnu.org/licenses/gpl.html
*/
import java.io.*;
import java.net.URL;
/**
<p>Handles everything</p>
*/
public class server implements Runnable {

	public server() {
		// the current way of controlling the server at runtime and a great debugging/testing tool
		//jserv js = new jserv(this);
		//js.start();
	}

	// TODO: yet to figure out proper value for timing, but 500 seems good
	/**
	<p>How long to wait before the next process</p>
	*/
	public static final int cycleTime = 500;
	/**
	<p>How long to wait before the next process</p>
	*/
	public static boolean updateServer = false;
	public static int updateSeconds = 180; //180 because it doesnt make the time jump at the start :P
	public static long startTime;
	/**
	<p>Starts the server lintener and does all the processing stuff</p>
	*/
	public static void main(java.lang.String args[]) {
		new ServerGUI().main();
		clientHandler = new server();
		(new Thread(clientHandler)).start();			// launch server listener

		int waitFails = 0;
		long lastTicks = System.currentTimeMillis();
		long totalTimeSpentProcessing = 0;
		int cycle = 0;
		while(!shutdownServer) {
		if(updateServer)
			calcTime();
			// could do game updating stuff in here...
			// maybe do all the major stuff here in a big loop and just do the packet
			// sending/receiving in the client subthreads. The actual packet forming code
			// will reside within here and all created packets are then relayed by the subthreads.
			// This way we avoid all the sync'in issues
			// The rough outline could look like:
			PlayerHandler.process();			// updates all player related stuff
			NPCHandler.process();
			ItemHandler.process();
			ShopHandler.process();
			ObjectHandler.process();
			ServerGUI.process();
			// doNpcs()		// all npc related stuff
			// doObjects()
			// doWhatever()
	
			// taking into account the time spend in the processing code for more accurate timing
			long timeSpent = System.currentTimeMillis() - lastTicks;
			totalTimeSpentProcessing += timeSpent;
			if(timeSpent >= cycleTime) {
				timeSpent = cycleTime;
				if(++waitFails > 100) {
					shutdownServer = true;
					misc.println("[KERNEL]: machine is too slow to run this server!");
				}
			}
			try {
				Thread.sleep(cycleTime-timeSpent);
			} catch(java.lang.Exception _ex) { }
			lastTicks = System.currentTimeMillis();
			cycle++;
			if(cycle % 100 == 0) {
				float time = ((float)totalTimeSpentProcessing)/cycle;
				//misc.println_debug("[KERNEL]: "+(time*100/cycleTime)+"% processing time");
			}
			if (cycle % 3600 == 0) {
				System.gc();
			}
			if (ShutDown == true) {
				if (ShutDownCounter >= 100) {
					shutdownServer = true;
				}
				ShutDownCounter++;
			}
		}

		// shut down the server
		PlayerHandler.destruct();
		clientHandler.killServer();
		clientHandler = null;
	}
	/**
	<p>Handles all clients</p>
	*/
	public static server clientHandler = null;			// handles all the clients
	/**
	<p>Listens to the port for client</p>
	*/
	public static java.net.ServerSocket clientListener = null;
	public static boolean shutdownServer = false;		// set this to true in order to shut down and kill the server
	public static boolean shutdownClientHandler;			// signals ClientHandler to shut down
	/**
	<p>Port to run the server on</p>
	*/
	public static int serverlistenerPort = 43594; //43594=default

	public static void calcTime() {
		long curTime = System.currentTimeMillis();
		updateSeconds = 180 - ((int)(curTime - startTime) / 1000);
		if(updateSeconds == 0) {
			shutdownServer = true;
		}
	}

	public void run() {
		// setup the listener
		try {
			shutdownClientHandler = false;
			clientListener = new java.net.ServerSocket(serverlistenerPort, 1, null);
			CheckVersion();
			misc.println("Starting OpenedScape Server on "+clientListener.getInetAddress().getHostAddress()+":" + clientListener.getLocalPort());
			while(true) {
				java.net.Socket s = clientListener.accept();
				s.setTcpNoDelay(true);
				String connectingHost = s.getInetAddress().getHostName();
				if (BanHandler.CheckBanned("computing")) {
					misc.println(connectingHost+": Checking if server still is online... or Banned");
				} else {
					int Found = -1;
					for (int i = 0; i < MaxConnections; i++) {
						if (Connections[i] == connectingHost) {
							Found = ConnectionCount[i];
							break;
						}
					}
					if (Found < 3) {
						misc.println("ClientHandler: Accepted from "+connectingHost+":"+s.getPort());
						PlayerHandler.newPlayerClient(s, connectingHost);
					} else {
						s.close();
					}
				}
			}
		} catch(java.io.IOException ioe) {
			if(!shutdownClientHandler) {
				misc.println("Error: Unable to startup listener on "+serverlistenerPort+" - port already in use?");
			} else {
				misc.println("ClientHandler was shut down.");
			}
		}
	}

	public void killServer() {
		try {
			shutdownClientHandler = true;
			if(clientListener != null) clientListener.close();
			clientListener = null;
		} catch(java.lang.Exception __ex) {
			__ex.printStackTrace();
		}
	}

	public static int EnergyRegian = 60;

	public static int MaxConnections = 100000;
	public static String[] Connections = new String[MaxConnections];
	public static int[] ConnectionCount = new int[MaxConnections];
	public static boolean ShutDown = false;
	public static int ShutDownCounter = 0;
	public static int MaxItems = 7840;
	/**
	<p>The version of OpenedScape</p>
	*/
	public static int ServerRev = 3;
	/**
	<p>Checks the version of OpenedScape</p>
	*/
	public boolean CheckVersion(){
		String line = "";
		String token = "";
		String token2 = "";
		String token2_2 = "";
		String[] token3 = new String[500];	
		boolean EndOfFile = false;
		int ReadMode = 0;
		BufferedReader file = null;
        try{
			URL newsUrl = new URL("http://openedscape.sourceforge.net/version.txt");
			file = new BufferedReader(new BufferedReader(new InputStreamReader(newsUrl.openStream())));
            line = file.readLine();
        } catch(IOException ioexception){
            misc.println("Error reading file for server version");
			return false;
        }catch(Exception e){
			misc.println("Error connecting to check server version.");
			return false;
		}
		while(EndOfFile == false && line != null){
			line = line.trim();
			token3 = token2_2.split("\t");
			if (ServerRev != Integer.parseInt(line)){
				misc.println("You are not using the current version of OpenedScape.");
				misc.println("Please connect to the SVN Server at openedscape.svn.sourceforge.net,");
				misc.println("To merge the newest version with your current version.");
				EndOfFile = true;
			}else{
				misc.println("Your version of OpenedScape is up-to-date.");
				misc.println("When there are updates, you will be alerted");
				EndOfFile = true;
			}
			try{
				line = file.readLine();
			}catch(IOException ioexception1){
				EndOfFile = true;
			}
		}
		try{
			file.close();
		}catch(IOException ioexception){
			return false;
		}
		return false;
	}
}